package com.javaspeak.concurrency.synchronizedperformance.uncontended;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.internal.TextListener;
import org.junit.runner.JUnitCore;

import com.javaspeak.concurrency.synchronizedperformance.uncontended.UncontendedCounter;


/**
 * This test tries to establish whether there is performance cost on calling
 * a synchronized method if there is no contention.  In this example there is
 * no contention as the synchronized method is only being called by one thread.
 * <p>
 * The results for jdk 1.7 on on a core i5 with 4 cores:
 * <ul>
 *   <li>Uncontended Synchronized method call, called 100000000 times in 2459 
 *       milli seconds
 *    <li>Normal Method call, called 100000000 times in 2527 milli seconds
 * </ul>   
 * What this means is that the performance effect of marking a method 
 * synchronized is negligible if there is no contention.
 * 
 * @author John Dickerson
 */
public class UncontentedSynchronizedTest {
    
    public Logger logger = Logger.getLogger( UncontentedSynchronizedTest.class );
    
    @Test
    public void testUncontentedSynchronized(){
        
        UncontendedCounter uncontentedSynchronized = 
                new UncontendedCounter();
        
        long startUncontentedSynchronizedNanoTime = System.nanoTime();
        
        int numberCalls = 100 * 1000000;
        
        for ( int i=0; i<numberCalls; i++ ){
            
            uncontentedSynchronized.doSomethingUncontenedSynchronized();
        }
        
        long endUncontentedSynchronizedNanoTime = System.nanoTime();
        
        long startNanoTime = System.nanoTime();
        
        for ( int i=0; i<numberCalls; i++ ){
            
            uncontentedSynchronized.doSomethingUncontenedSynchronized();
        }
       
        long endNanoTime = System.nanoTime();
        
        long uncontentedSynchronizedTimeMilliseconds = 
                ( endUncontentedSynchronizedNanoTime - 
                    startUncontentedSynchronizedNanoTime ) / 1000000;
        
        long timeMilliseconds = ( endNanoTime - startNanoTime ) / 1000000;
        
        logger.debug( 
             "Uncontended Synchronized method call, called " + numberCalls + 
                 " times in " + uncontentedSynchronizedTimeMilliseconds + 
                     " milli seconds" );
        
        logger.debug( 
                "Normal Method call, called " + numberCalls + 
                    " times in " + timeMilliseconds + 
                        " milli seconds" );
    }

    public static void main( String args[] ){
        
        BasicConfigurator.resetConfiguration();
        BasicConfigurator.configure();

        JUnitCore junitCore = new JUnitCore();
        junitCore.addListener( new TextListener( System.out ) );
        junitCore.run( UncontentedSynchronizedTest.class );
    }
}
